﻿package lobby
{
	import flash.display.MovieClip;
	import flash.display.SimpleButton;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.EventPhase;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	import flash.ui.Mouse;
	
	/**
	 *
	 * Author: fx.barrett ( http://www.wisebisoft.com/ )
	 * Created on: Wednesday, September 03, 2008, 4:22 AM (GTM +2:00) Minsk
	 * Description: Reusable ActionScript 3.0 ScrollBar class
	 * Usage: Simply instantiate the class and pass all the 5 required arguments ( and you can set 6 additional properties too ).
	 * Example: new CustomScrollBar(stage, content_mc, content_mask, scroll_track, scroll_btn, true, true, true, true, .2, 5);
	 *
	 * ---------------- ONLY 5 PARAMETERS ARE REQUIRED FOR THE CLASS TO FUNCTION ----------------------
	 *
	 * -- stage -- is your Stage object, it will help you prevent people from messing up certain features
	 * -- content_mc -- is the movie clip holding the content that you want to scroll
	 * -- content_mask -- is the movie clip that you'll use to mask content_mc movie clip
	 * -- scroll_track -- is the movie clip that plays the role of a track for the scroll_btn
	 * -- scroll_btn -- is the button that you can click + hold and drag to scroll your content_mc movie clip
	 *
	 * -- -------------- ALL THE PARAMETERS AFTER THE 5TH PARAMETER ARE OPTIONAL ---------------------------------------
	 *
	 * -- the following 4 parameters in the line enable or disable certain features like mouse wheel scrolling or blurring
	 * -- .3 -- is the easing that will be added to the content_mc movie clip; the lower the value is the more easing is applied
	 * -- 10 -- is the number of pixels the scroll_btn will move on the Y axis each time you scroll with the mouse wheel
	 * Edited: loc.nguyen, add up/down button
	 * */
	
	public class CustomScrollBar
	{
		private var content:MovieClip;
		private var contentMask:MovieClip;
		private var scrollTrack:MovieClip;
		private var scrollButton:MovieClip;
		private var upButton:SimpleButton;
		private var downButton:SimpleButton;
		private var scrollAmount:Number;
		private var isAutoScroll:Boolean;
		private var useMouseWheel:Boolean; // helps you enable or disable the mouse wheel scrolling feature
		private var enableJumping:Boolean; // helps you enable or disable the "jumping feature"
		private var buttonModeEnabled:Boolean; // helps you enable or disable the scroll button's buttonMode property
		private var easing:Number;
		private var scrollSpeed:Number;
		private var scrollSpeedAuto:Number;
		private var scrollSpeedManual:Number;
		private var moveValue:Number; // helps calculate the final moveSpeed value
		private var moveSpeed:Number; // the speed with which the content will be scrolled
		private var currentContentY:Number; // stores the current position of the content movie clip
		private var scrollTrackScaleY:Number;
		private var contentHeight:Number;
		private var scrollTrackHeight:Number;
		private var scrollButtonHeight:Number;
		private var contentMaskHeight:Number;
		private var movieStage:Stage;
		private var enterFrameActive:Boolean; // it "signals" if the ENTER_FRAME event has been triggered or not
		private var allowRemove:Boolean; // helps your function know when it is allowed to remove the ENTER_FRAME event
		
		private var scrollDir:int;
		
		// CLASS CONSTRUCTOR //
		
		public function CustomScrollBar(movieStage:Stage, content:MovieClip, contentMask:MovieClip, scrollTrack:MovieClip, scrollButton:MovieClip, upButton:SimpleButton, downButton:SimpleButton, scrollAmount:Number, isAutoScroll:Boolean = false, // auto scroll if user not scroll
			useMouseWheel:Boolean = true, // mouse wheel scrolling is by default: ENABLED
			enableJumping:Boolean = true, // the "jumping feature" is by default: ENABLED
			buttonModeEnabled:Boolean = true, // scroll button's buttonMode property is by default: ENABLED
			easing:Number = .15, // easing speed is by default set to: .15
			scrollSpeed:Number = 5 // scrolling speed is be default set to: 5
			
			)
		{
			// store certain properties of the objects passed to the class constructor
			// in specific variables, increasing performance at the same time
			this.isAutoScroll = isAutoScroll;
			this.content = content;
			this.contentMask = contentMask;
			this.scrollTrack = scrollTrack;
			this.scrollButton = scrollButton;
			this.scrollButton.cacheAsBitmap = true;
			
			if (upButton != null)
			{
				this.upButton = upButton;
			}
			if (downButton != null)
			{
				this.downButton = downButton;
			}
			
			this.scrollAmount = scrollAmount;
			this.useMouseWheel = useMouseWheel;
			this.enableJumping = enableJumping;
			this.buttonModeEnabled = buttonModeEnabled;
			this.easing = easing;
			this.scrollSpeed = scrollSpeed;
			this.movieStage = movieStage;
			
			setHeights();
			setButtonMode();
			setContentMask();
			storeTrackScaleY();
			repositionObjects();
			addListeners();
		}
		
		// store the height of your objects
		private function setHeights():void
		{
			contentHeight = content.height;
			contentMaskHeight = contentMask.height;
			scrollTrackHeight = scrollTrack.height;
			scrollButtonHeight = scrollButton.height;
			
			var scroll_step:Number = (contentHeight - contentMaskHeight) / scrollAmount;
			scrollSpeedManual = (scrollTrackHeight - scrollButtonHeight) / scroll_step;
			scrollSpeedAuto = scrollSpeedManual / 3;
			scrollSpeed = scrollSpeedManual;
		}
		
		// enable or disable the buttonMode property of your scroll button
		private function setButtonMode():void
		{
			scrollButton.buttonMode = buttonModeEnabled;
		}
		
		// apply the mask movie clip to the content movie clip
		private function setContentMask():void
		{
			// cache both the content and content mask so that you'll
			// be able to apply masks that container an alpha channel too
			
			content.cacheAsBitmap = true;
			contentMask.cacheAsBitmap = true;
			content.mask = contentMask;
		}
		
		// reposition your objects so that everything will scroll correctly
		private function repositionObjects():void
		{
			//contentMask.x = content.x;
			//scrollButton.x = scrollTrack.x;
			//content.y = contentMask.y = scrollTrack.y = scrollButton.y = 0;
			//if (contentHeight > contentMaskHeight) {
			//content.y = 0;
			content.y = contentMask.y;
			scrollButton.y = 0;
			currentContentY = contentMask.y;
			//currentContentY = 0;
			//}
		}
		
		// store the scaleY property of the scroll track movie clip
		private function storeTrackScaleY():void
		{
			scrollTrackScaleY = scrollTrack.scaleY;
		}
		
		// add all the event listeners that will be handling the scrolling
		private function addListeners():void
		{
			enterFrameActive = false;
			
			// check to see if the actual height of the content is more than the
			// height of the content mask; if the content height is less, that means that there
			// is no use for a scroll track and nor for a scroll button, so we'll make them invisible
			// ... otherwise, add all the required listeners that will handle the scrolling
			
			if (contentHeight <= contentMaskHeight)
			{
				scrollTrack.visible = false;
				scrollButton.visible = false;
				
				if (upButton && downButton)
				{
					upButton.enabled = false;
					downButton.enabled = false;
				}
			}
			else
			{
				scrollTrack.visible = true;
				scrollButton.visible = true;
				
				if (upButton && downButton)
				{
					upButton.enabled = true;
					downButton.enabled = true;
				}
				
				if (useMouseWheel == true)
				{
					content.addEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler);
				}
				
				if (enableJumping == true)
				{
					scrollTrack.addEventListener(MouseEvent.MOUSE_DOWN, scrollTrackMouseHandler);
				}
				
				if (upButton && downButton)
				{
					upButton.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDownUpButtonHandler);
					downButton.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDownDownButtonHandler);
				}
				scrollButton.addEventListener(MouseEvent.MOUSE_DOWN, startDragHandler);
				scrollButton.addEventListener(MouseEvent.MOUSE_UP, stopDragHandler);
				movieStage.addEventListener(MouseEvent.MOUSE_UP, stopDragHandler);
			}
		}
		
		// the moveContentHandler function is responsible for moving the content movie clip
		// some easing is added too ( just to make it look better ) and an optional blur filter
		private function moveContentHandler(event:Event):void
		{
			// store the current Y position of the content movie clip
			currentContentY = content.y;
			
			moveValue = (contentHeight - contentMaskHeight) / (scrollTrackHeight - scrollButtonHeight);
			moveSpeed = (scrollButton.y * (-moveValue) - content.y) * easing;
			content.y += moveSpeed;
			
			removeContentEnterFrame();
		}
		
		private function onMouseDownUpButtonHandler(evt:MouseEvent):void
		{
			allowRemove = true;
			addContentEnterFrame();
			
			scrollButton.y -= scrollSpeed * 5;
			
			if (scrollButton.y <= 0)
			{
				scrollButton.y = 0;
			}
			else if (scrollButton.y >= (scrollTrackHeight - scrollButtonHeight))
			{
				scrollButton.y = scrollTrackHeight - scrollButtonHeight;
			}
			
			upButton.addEventListener(MouseEvent.MOUSE_UP, onMouseOutButtonHandler);
			upButton.addEventListener(MouseEvent.MOUSE_OUT, onMouseOutButtonHandler);
			
			scrollDir = -1;
		}
		
		private function onMouseDownDownButtonHandler(evt:MouseEvent):void
		{
			allowRemove = true;
			addContentEnterFrame();
			
			scrollButton.y += scrollSpeed * 5;
			
			if (scrollButton.y <= 0)
			{
				scrollButton.y = 0;
			}
			else if (scrollButton.y >= (scrollTrackHeight - scrollButtonHeight))
			{
				scrollButton.y = scrollTrackHeight - scrollButtonHeight;
			}
			
			downButton.addEventListener(MouseEvent.MOUSE_UP, onMouseOutButtonHandler);
			downButton.addEventListener(MouseEvent.MOUSE_OUT, onMouseOutButtonHandler);
			
			scrollDir = 1;
		}
		
		private function onMouseOutButtonHandler(evt:MouseEvent):void
		{
			evt.currentTarget.removeEventListener(MouseEvent.MOUSE_UP, onMouseOutButtonHandler);
			evt.currentTarget.removeEventListener(MouseEvent.MOUSE_OUT, onMouseOutButtonHandler);
			allowRemove = true;
		}
		
		// function responsible for moving the scroll button movie clip if the
		// visitor uses the mouse wheel to scroll the content movie clip
		private function mouseWheelHandler(event:MouseEvent):void
		{
			allowRemove = true;
			addContentEnterFrame();
			
			scrollButton.y += event.delta * (-scrollSpeed);
			
			if (scrollButton.y <= 0)
			{
				scrollButton.y = 0;
			}
			else if (scrollButton.y >= (scrollTrackHeight - scrollButtonHeight))
			{
				scrollButton.y = scrollTrackHeight - scrollButtonHeight;
			}
		}
		
		// function responsible for the "jumping feature", meaning that you can click any point on
		// the scroll track movie clip and the scroll button will be moved to that certain point, updating
		// the content movie clip's positions at the same time
		private function scrollTrackMouseHandler(event:MouseEvent):void
		{
			if (event.eventPhase == EventPhase.AT_TARGET)
			{
				addContentEnterFrame();
				
				// check for the coordinates of the visitor's CLICK event on the scroll track movie clip, if the coordinates are
				// close to the top of the scroll track then the scroll button will be moved to the top of the track...
				// ...else if the click event had place close to the bottom of the track then the scroll button will be placed at 
				// the bottom of the track... else, it will be moved to the exact point from where the visitor has fired the CLICK event
				
				if (event.target.mouseY * scrollTrackScaleY <= (scrollTrackHeight - scrollButtonHeight / 2) && event.target.mouseY * scrollTrackScaleY >= (scrollButtonHeight / 2))
				{
					scrollButton.y = event.target.mouseY * scrollTrackScaleY - scrollButtonHeight / 2;
				}
				else if (event.target.mouseY * scrollTrackScaleY <= (scrollButtonHeight / 2))
				{
					scrollButton.y = 0;
				}
				else if (event.target.mouseY * scrollTrackScaleY >= (scrollTrackHeight - scrollButtonHeight / 2))
				{
					scrollButton.y = scrollTrackHeight - scrollButtonHeight;
				}
			}
		}
		
		// function responsible for the drag feature of the scroll button
		private function startDragHandler(event:MouseEvent):void
		{
			allowRemove = false;
			addContentEnterFrame();
			scrollButton.startDrag(false, new Rectangle(0, scrollTrack.y, 0, (scrollTrackHeight - scrollButtonHeight)));
		}
		
		// function responsible for stopping the scroll button from dragging once the visitor releases it
		private function stopDragHandler(event:MouseEvent):void
		{
			scrollButton.stopDrag();
			allowRemove = true;
		}
		
		// function responsible for adding the ENTER_FRAME event that is responsible
		// for moving ( positioning ) the content movie clip
		private function addContentEnterFrame():void
		{
			if (enterFrameActive == false)
			{
				enterFrameActive = true;
				content.addEventListener(Event.ENTER_FRAME, moveContentHandler);
			}
		}
		
		// this function will remove the ENTER_FRAME event once the content movie clip stops scrolling
		private function removeContentEnterFrame():void
		{
			if (currentContentY == content.y && allowRemove == true)
			{
				content.removeEventListener(Event.ENTER_FRAME, moveContentHandler);
				enterFrameActive = false;
				allowRemove = false;
			}
		}
		
		// this is a simple function that removes all the listeners from all the objects
		// essentially, this function will be of much help if you want to use the same scrollbar instance
		// for all the content that will be displayed in your project
		public function kill():void
		{
			if (upButton && downButton)
			{
				upButton.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDownUpButtonHandler);
				downButton.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDownDownButtonHandler);
			}
			content.removeEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler);
			scrollTrack.removeEventListener(MouseEvent.MOUSE_DOWN, scrollTrackMouseHandler);
			content.removeEventListener(Event.ENTER_FRAME, moveContentHandler);
			scrollButton.removeEventListener(MouseEvent.MOUSE_DOWN, startDragHandler);
			scrollButton.removeEventListener(MouseEvent.MOUSE_UP, stopDragHandler);
			movieStage.removeEventListener(MouseEvent.MOUSE_UP, stopDragHandler);
		}
		
		// a public function responsible for updating the scrollbar, adding the event listeners again to each object,
		// repositioning all the objects, storing new values and enabling or disabling certain scrollbar features; 
		// all this is done ONLY after we remove the current event listeners with the help of the kill(); function
		public function update():void
		{
			kill();
			setHeights();
			setButtonMode();
			storeTrackScaleY();
			repositionObjects();
			addListeners();
		}
		
		// public setter methods that will help you update the scrollbar, enable of disable features and add new values
		
		public function set setEasing(value:Number):void
		{
			easing = value
		}
		;
		
		public function set setScrollSpeed(value:Number):void
		{
			scrollSpeed = value
		}
		;
		
		public function set setMouseWheel(value:Boolean):void
		{
			useMouseWheel = value
		}
		;
		
		public function set setJumping(value:Boolean):void
		{
			enableJumping = value
		}
		;
		
		public function set setScrollButtonMode(value:Boolean):void
		{
			buttonModeEnabled = value
		}
		;
		
		// public getter methods that you'll most likely not use very often but it's good to have them there;
		// if you run into problems / bugs then you can try debugging your application with the help of these getter
		// methods ( but if you are more familiar with the built-in Flash / Flex debugger then it's much better to use that instead )
		
		public function get getEasing():Number
		{
			return easing
		}
		;
		
		public function get getScrollSpeed():Number
		{
			return scrollSpeed
		}
		;
		
		public function get getMouseWheel():Boolean
		{
			return useMouseWheel
		}
		;
		
		public function get getJumping():Boolean
		{
			return enableJumping
		}
		;
		
		public function get getScrollButtonMode():Boolean
		{
			return buttonModeEnabled
		}
		;
		
		public function resetPosition():void
		{
			//content.y = 0;
			content.y = contentMask.y;
		}
	}
}